package kr.ac.hanyang.cs.park;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Calendar; 

import android.view.KeyEvent;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.Button;

public class RunTask extends Activity {

	private boolean bRecordingBtnClicked								= false;
	private boolean bCheckRecordedClicked								= false;
	
	private boolean isFirstButtonTapped									= true;
	private boolean isSecondButtonTapped								= false;
	private boolean isThirdButtonTapped									= false;
	
	private String secondApplicationName								= null;
	private String thirdApplicationName									= null;
	
	private Button recordBtn											= null;
	private Thread voiceCommand											= null;
	private AlertDialog alert 											= null;
	private int waitCount												= 0;									
	private int standardForNormalization								= 10000;
	
	//keyTheory values
	private ArrayList<Short> biggestValues								= new ArrayList<Short>();
	
	@Override
    public void onBackPressed()
	{
        // disable back key
		Log.i("KEYTEST", "BACK KEY IS PRESSED");
		
		if (bRecordingBtnClicked == true)
		{
			Log.i("KEYTEST", "Now Recording");
			
			return;
		}
		else
		{
			super.onBackPressed();
		}
    }  
	
	/** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.runtask);

        recordBtn														= (Button)findViewById(R.id.btnRecord);

        recordBtn.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				if (bRecordingBtnClicked == false) {
					recordBtn.setText("명령어 입력 중...");
					bRecordingBtnClicked								= true;
					
					voiceCommand										= new Thread(new VoiceCommand());
					voiceCommand.setDaemon(true);
					voiceCommand.start();
				}
				else {
					recordBtn.setText("처리 중...");
					recordBtn.setEnabled(false);
					recordBtn.setFocusable(false);
					bRecordingBtnClicked								= false;
					voiceCommand.interrupt();
				}
			}
		});

    }

    public class VoiceCommand implements Runnable {

    	private final int RECORDER_AUDIO_ENCODING						= AudioFormat.ENCODING_PCM_16BIT;
    	private final int RECORDER_CHANNELS								= AudioFormat.CHANNEL_IN_MONO;
    	private final int WAVE_CHANNEL_MONO								= 1;
    	private final int HEADER_SIZE									= 0x2c;	//44
    	private final int RECORDER_BPP									= 16;
    	private final int RECORDER_SAMPLERATE							= 0x3E80;
																				/*
																				 * 0x1F40  //  8000 samples/sec 
																				 * 0x2B11  // 11025 samples/sec 
																				 * 0x3E80  // 16000 samples/sec 
																				 * 0x5622  // 22050 samples/sec 
																				 * 0x7D00  // 32000 samples/sec 
																				 * 0xAC44  // 44100 samples/sec 
																				 * 0xBB80  // 48000 samples/sec 
																				 */

    	private boolean bNowRecording									= false;

    	private AudioRecord oAudioRecord								= null;
    	private int iBufferSize											= -1;
    	private int iAudioSize											= -1;
    	private final String sTmpWaveFileName							= "sesameTemp";
    	private BufferedInputStream oInputBufferStream					= null;
    	private BufferedOutputStream oOutputBufferStream				= null;
    	private String sTimestamp										= "";


    	public String getTimestamp() {
    	    String sTimestamp											= "";
    		Calendar oCalendar											= Calendar.getInstance();

    		sTimestamp													= String.format("%04d%02d%02d_%02d%02d%02d_%04d",
																					oCalendar.get(Calendar.YEAR)
																					, (oCalendar.get(Calendar.MONTH) + 1)
																					, oCalendar.get(Calendar.DAY_OF_MONTH)
																					, oCalendar.get(Calendar.HOUR_OF_DAY)
																					, oCalendar.get(Calendar.MINUTE)
																					, oCalendar.get(Calendar.SECOND)
																					, oCalendar.get(Calendar.MILLISECOND));

    		Log.d("TIMESTAMP", sTimestamp);
    	    return sTimestamp;
    	}
    	

    	public void recordReady() {
    		bNowRecording												= false;
    		iBufferSize													= AudioRecord.getMinBufferSize(RECORDER_SAMPLERATE
    																							, RECORDER_CHANNELS
    																							, RECORDER_AUDIO_ENCODING); //4096 byte (or 4096*4 byte?)

    		oAudioRecord												= new AudioRecord(MediaRecorder.AudioSource.MIC
    																							, RECORDER_SAMPLERATE
    																							, RECORDER_CHANNELS
    																							, RECORDER_AUDIO_ENCODING
    																							, iBufferSize);

    		sTimestamp													= getTimestamp();
    	}

    	public void recordStart() {
    		recordReady();    		
    		if (oAudioRecord == null) {
    			Log.e("ERROR", "Should call recordReady() to initialize AudioRecord object.");
    			return ;
    		}
    		
    		this.

    		bNowRecording												= true;
    		oAudioRecord.startRecording();
    	}


    	public void recordStop() {
    		bNowRecording												= false;
    	}


    	public short[] recordToShort() {
    		short[] recordData											= new short[iBufferSize];
    		
    		try {
    			while (bRecordingBtnClicked) {
    				if (oAudioRecord.read(recordData, 0, iBufferSize) == AudioRecord.ERROR_INVALID_OPERATION) {
    					Log.e("ERROR", "INVALID read operation while reading");
    				}
    			}
    			recordStop();
    		}
    		catch(Exception e) {
    			e.printStackTrace();
    		}
    		
    		for (int i = 0;i < recordData.length;i++) {
    			Log.i("INFO", "Short data ["+ i +"]: "+ recordData[i]);
    		}
    		
    		return recordData;
    	}


    	public File recordToFile() {
    		byte[] recordData											= new byte[iBufferSize]; 
    		File oRawFile												= new File(Environment.getExternalStorageDirectory() +"/_sesame/"+ sTmpWaveFileName +"_"+ sTimestamp +".tmp");

    		try {
    			// write record data to raw file 
    			oOutputBufferStream										= new BufferedOutputStream(new FileOutputStream(oRawFile));

    			while (bRecordingBtnClicked) {
    				if (oAudioRecord.read(recordData, 0, iBufferSize) != AudioRecord.ERROR_INVALID_OPERATION) {
    					oOutputBufferStream.write(recordData, 0, iBufferSize);
    				}
    			}
    			oOutputBufferStream.flush();
    			oOutputBufferStream.close();
    			oAudioRecord.stop();
    			recordStop();
    		}
    		catch (Exception e) {
    			e.printStackTrace();
    		}

    		return oRawFile;
    	}

    	
    	private short[] convertToShort(File oRawFile) {
    		int iRawDataSize											= (int) oRawFile.length();
    		int iSampleCnt												= iRawDataSize / 2;
    		int iOffset													= 0;
    		int iReadCnt												= 0;
    		byte[] aRawInByte											= new byte[iRawDataSize];
    		short[] aRawInShort											= new short[iSampleCnt];
    		FileInputStream oRawFIS										= null;

    		if (oRawFile.length() > Integer.MAX_VALUE) {
    			Log.e("ERROR", "File size has been exceeded");
    		}

    		try {
    			oRawFIS													= new FileInputStream(oRawFile);

    			while (iOffset < aRawInByte.length
						&& (iReadCnt = oRawFIS.read(aRawInByte, iOffset, aRawInByte.length-iOffset)) >= 0) {
					iOffset												+= iReadCnt;
				}

				// convert from big endian to little endian in encoding by 16bits
    			/*
    			for (int i = 0;i < iSampleCnt;i++) {
					int MSB												= aRawInByte[2*i];
					int LSB												= aRawInByte[2*i + 1];
					aRawInShort[i]										= (short)(MSB << 8 | (255 & LSB));
				}
				*/
    			ByteBuffer.wrap(aRawInByte).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(aRawInShort);
    		}
    		catch (Exception e) {
    			e.printStackTrace();
    		}

    		return aRawInShort;
    	}

    	
    	private void convertToWav(short[] aVoiceDataInShort) {
    	    byte[] aVoiceDataInByte										= new byte[aVoiceDataInShort.length * 2];
    	    ByteBuffer.wrap(aVoiceDataInByte).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().put(aVoiceDataInShort);
    	    File aWavFile												= new File(Environment.getExternalStorageDirectory() +"/_sesame/"+ sTmpWaveFileName +"_"+ sTimestamp +"_Comp.wav");

    		try {
    			// TODO: update iAudioSize
    			//iAudioSize												= aVoiceDataInShort.length * 2;		// is this right?
    			
				oOutputBufferStream										= new BufferedOutputStream(new FileOutputStream(aWavFile));
				oOutputBufferStream.write(getWaveHeader());
				oOutputBufferStream.write(aVoiceDataInByte);
				oOutputBufferStream.flush();
				oOutputBufferStream.close();
				oInputBufferStream.close();
    		}
    		catch (Exception e) {
    			e.printStackTrace();
    		}

    	}


    	public void convertToWav(File oRawFile) {
    		byte[] recordBuffer											= new byte[iBufferSize];
    		File oWavFile												= new File(Environment.getExternalStorageDirectory() +"/_sesame/"+ sTmpWaveFileName +"_"+ sTimestamp +".wav");

    		try {
				// copy raw data to wav file
				iAudioSize												= (int) oRawFile.length();	// the size of tempFile in bytes

				oInputBufferStream										= new BufferedInputStream(new FileInputStream(oRawFile));
				oOutputBufferStream										= new BufferedOutputStream(new FileOutputStream(oWavFile));
				oOutputBufferStream.write(getWaveHeader());
				while (oInputBufferStream.read(recordBuffer) != -1) {
					oOutputBufferStream.write(recordBuffer);
				}
				oOutputBufferStream.flush();
				oOutputBufferStream.close();
				oInputBufferStream.close();
    		}
    		catch (Exception e) {
    			e.printStackTrace();
    		}

    	}
    	

    	private byte[] getWaveHeader() {
    		byte[] header												= new byte[HEADER_SIZE];
    		int iTotalSize												= iAudioSize + 40;
    		long byteRate												= RECORDER_BPP * RECORDER_SAMPLERATE * WAVE_CHANNEL_MONO / 8; // 16 * 44100 * 1 / 8 = 88200
    		header[0]													= 'R'; // RIFF/WAVE header
    		header[1]													= 'I';
    		header[2]													= 'F';
    		header[3]													= 'F';
    		header[4]													= (byte) (iTotalSize & 0xff);
    		header[5]													= (byte) ((iTotalSize >> 8) & 0xff);
    		header[6]													= (byte) ((iTotalSize >> 16) & 0xff);
    		header[7]													= (byte) ((iTotalSize >> 24) & 0xff);
    		header[8]													= 'W';
    		header[9]													= 'A';
    		header[10]													= 'V';
    		header[11]													= 'E';
    		header[12]													= 'f'; // 'fmt ' chunk
    		header[13]													= 'm';
    		header[14]													= 't';
    		header[15]													= ' ';
    		header[16]													= 16; // 4 bytes: size of 'fmt ' chunk
    		header[17]													= 0;
    		header[18]													= 0;
    		header[19]													= 0;
    		header[20]													= (byte) 1; // format = 1 (PCMπÊΩƒ)
    		header[21]													= 0;
    		header[22]													= WAVE_CHANNEL_MONO;
    		header[23]													= 0;
    		header[24]													= (byte) (RECORDER_SAMPLERATE & 0xff);
    		header[25]													= (byte) ((RECORDER_SAMPLERATE >> 8) & 0xff);
    		header[26]													= (byte) ((RECORDER_SAMPLERATE >> 16) & 0xff);
    		header[27]													= (byte) ((RECORDER_SAMPLERATE >> 24) & 0xff);
    		header[28]													= (byte) (byteRate & 0xff);
    		header[29]													= (byte) ((byteRate >> 8) & 0xff);
    		header[30]													= (byte) ((byteRate >> 16) & 0xff);
    		header[31]													= (byte) ((byteRate >> 24) & 0xff);
    		header[32]													= (byte) RECORDER_BPP * WAVE_CHANNEL_MONO / 8; // block align = 16 * 1 / 8													= 2
    		header[33]													= 0;
    		header[34]													= RECORDER_BPP; // bits per sample = 16
    		header[35]													= 0;
    		header[36]													= 'd';
    		header[37]													= 'a';
    		header[38]													= 't';
    		header[39]													= 'a';
    		header[40]													= (byte) (iAudioSize & 0xff);
    		header[41]													= (byte) ((iAudioSize >> 8) & 0xff);
    		header[42]													= (byte) ((iAudioSize >> 16) & 0xff);
    		header[43]													= (byte) ((iAudioSize >> 24) & 0xff);
    		return header;
    	}

    	Handler mHandler = new Handler()
    	{
            public void handleMessage(Message msg)
            {
            	switch (msg.what)
            	{
            		case -100:
            		{
            			alert = new AlertDialog.Builder(RunTask.this)
//		        	     .setIcon(R.drawable.app_icon)
		        	     .setTitle("입력한 음성에 해당하는 동작이 없습니다.")
		        	     .setMessage("다시 입력해주세요.")
		        	     .setPositiveButton("다시 입력하기", new DialogInterface.OnClickListener() {      
		        	        @Override
		        	        public void onClick(DialogInterface dialog, int which) {
		        	          // TODO Auto-generated method stub
		        	          dialog.dismiss();
		        	          waitCount = -100;
		        	          
		        	          isFirstButtonTapped = false;
		        	        }
		        	     })
		        	     .setCancelable(false)
		        	     .show();
            			break;
            		}
            		
	            	case -1:
	    			{
	    	    		recordBtn.setEnabled(true);
	    	    		recordBtn.setFocusable(true);
	    	    		recordBtn.setText("누르고 명령어를 말하세요");
	    	    		break;
	    			}
	    			
					case 0:
		        		 alert = new AlertDialog.Builder(RunTask.this)
//		        	     .setIcon(R.drawable.app_icon)
		        	     .setTitle("이 앱이 맞나요? 맞다면 잠시만 기다려주세요.")
		        	     .setMessage("인터넷")
		        	     .setPositiveButton("다시 입력하기", new DialogInterface.OnClickListener() {      
		        	        @Override
		        	        public void onClick(DialogInterface dialog, int which) {
		        	          // TODO Auto-generated method stub
		        	          dialog.dismiss();
		        	          waitCount = -100;
		        	          
		        	          isFirstButtonTapped = false;
		        	        }
		        	     })
		        	     .setNegativeButton(secondApplicationName, new DialogInterface.OnClickListener() {
		        	    	 @Override
		        	    	 public void onClick(DialogInterface dialog, int which)
		        	    	 {
		        	    		 isFirstButtonTapped	= false;
		        	    		 isSecondButtonTapped	= true;
		        	    		 
		        	    		 dialog.dismiss();
		        	    		 waitCount = -100;
		        	    		 
		        	    	 }
		        	     })
		        	     .setNeutralButton(thirdApplicationName, new DialogInterface.OnClickListener() {
		        	    	 @Override
		        	    	 public void onClick(DialogInterface dialog, int which)
		        	    	 {
		        	    		 isFirstButtonTapped	= false;
		        	    		 isThirdButtonTapped	= true;
		        	    		 
		        	    		 dialog.dismiss();
		        	    		 waitCount = -100;
		        	    	 }
		        	     })
		        	     .setCancelable(false)
		        	     .show();
						break;
						
					case 1:
						alert = new AlertDialog.Builder(RunTask.this)
//		        	     .setIcon(R.drawable.app_icon)
		        	     .setTitle("이 앱이 맞나요? 맞다면 잠시만 기다려주세요.")
		        	     .setMessage("카카오톡")
		        	     .setPositiveButton("다시 입력하기", new DialogInterface.OnClickListener() {      
		        	        @Override
		        	        public void onClick(DialogInterface dialog, int which) {
		        	          // TODO Auto-generated method stub
		        	          dialog.dismiss();
		        	          waitCount = -100;
		        	          
		        	          isFirstButtonTapped = false;
		        	        }
		        	     })
		        	     .setNegativeButton(secondApplicationName, new DialogInterface.OnClickListener() {      
			        	        @Override
			        	        public void onClick(DialogInterface dialog, int which) {
			        	          // TODO Auto-generated method stub
			        	          isFirstButtonTapped	= false;
			        	          isSecondButtonTapped	= true;
			        	          
			        	          dialog.dismiss();
			        	          waitCount = -100;
			        	        }
			        	     })
		        	     .setNeutralButton(thirdApplicationName, new DialogInterface.OnClickListener() {      
			        	        @Override
			        	        public void onClick(DialogInterface dialog, int which) {
			        	          // TODO Auto-generated method stub
			        	          isFirstButtonTapped	= false;
			        	          isThirdButtonTapped	= true;
			        	          
			        	          dialog.dismiss();
			        	          waitCount = -100;
			        	        }
			        	     })
		        	     .setCancelable(false)
		        	     .show();
						break;
						
					case 2:
//						alert = new AlertDialog.Builder(RunTask.this)
////		        	     .setIcon(R.drawable.app_icon)
//		        	     .setTitle("이 앱이 맞나요? 틀리면 버튼을 눌러주세요.")
//		        	     .setMessage("카메라")
//		        	     .setPositiveButton("다시 입력하기", new DialogInterface.OnClickListener() {      
//		        	        @Override
//		        	        public void onClick(DialogInterface dialog, int which) {
//		        	          // TODO Auto-generated method stub
//		        	          dialog.dismiss();
//		        	          waitCount = -100;
//		        	        }
//		        	     })
//		        	     .setCancelable(false)
//		        	     .show();
//						break;
//						
//					case 3:
						alert = new AlertDialog.Builder(RunTask.this)
//		        	     .setIcon(R.drawable.app_icon)
		        	     .setTitle("이 앱이 맞나요? 맞다면 잠시만 기다려주세요.")
		        	     .setMessage("사진찍기")
		        	     .setPositiveButton("다시 입력하기", new DialogInterface.OnClickListener() {      
		        	        @Override
		        	        public void onClick(DialogInterface dialog, int which) {
		        	          // TODO Auto-generated method stub
		        	          dialog.dismiss();
		        	          waitCount = -100;
		        	          
		        	          isFirstButtonTapped = false;
		        	        }
		        	     })
		        	     .setNegativeButton(secondApplicationName, new DialogInterface.OnClickListener() {      
			        	        @Override
			        	        public void onClick(DialogInterface dialog, int which) {
			        	          // TODO Auto-generated method stub
			        	          isFirstButtonTapped	= false;
			        	          isSecondButtonTapped	= true;
			        	          
			        	          dialog.dismiss();
			        	          waitCount = -100;
			        	        }
			        	     })
		        	     .setNeutralButton(thirdApplicationName, new DialogInterface.OnClickListener() {      
			        	        @Override
			        	        public void onClick(DialogInterface dialog, int which) {
			        	          // TODO Auto-generated method stub
			        	          isFirstButtonTapped	= false;
			        	          isThirdButtonTapped	= true;
			        	          
			        	          dialog.dismiss();
			        	          waitCount = -100;
			        	        }
			        	     })
		        	     .setCancelable(false)
		        	     .show();
						break;
						
					case 3:
						alert = new AlertDialog.Builder(RunTask.this)
//		        	     .setIcon(R.drawable.app_icon)
		        	     .setTitle("이 앱이 맞나요? 맞다면 잠시만 기다려주세요.")
		        	     .setMessage("지도찾기")
		        	     .setPositiveButton("다시 입력하기", new DialogInterface.OnClickListener() {      
		        	        @Override
		        	        public void onClick(DialogInterface dialog, int which) {
		        	          // TODO Auto-generated method stub
		        	          dialog.dismiss();
		        	          waitCount = -100;
		        	          
		        	          isFirstButtonTapped = false;
		        	        }
		        	     })
		        	     .setNegativeButton(secondApplicationName, new DialogInterface.OnClickListener() {      
			        	        @Override
			        	        public void onClick(DialogInterface dialog, int which) {
			        	          // TODO Auto-generated method stub
			        	          isFirstButtonTapped	= false;
			        	          isSecondButtonTapped	= true;
			        	          
			        	          dialog.dismiss();
			        	          waitCount = -100;
			        	        }
			        	     })
		        	     .setNeutralButton(thirdApplicationName, new DialogInterface.OnClickListener() {      
			        	        @Override
			        	        public void onClick(DialogInterface dialog, int which) {
			        	          // TODO Auto-generated method stub
			        	          isFirstButtonTapped	= false;
			        	          isThirdButtonTapped	= true;
			        	          
			        	          dialog.dismiss();
			        	          waitCount = -100;
			        	          
			        	        }
			        	     })
		        	     .setCancelable(false)
		        	     .show();
						break;
						
					case 4:
						alert = new AlertDialog.Builder(RunTask.this)
//		        	     .setIcon(R.drawable.app_icon)
		        	     .setTitle("이 앱이 맞나요? 맞다면 잠시만 기다려주세요.")
		        	     .setMessage("갤러리")
		        	     .setPositiveButton("다시 입력하기", new DialogInterface.OnClickListener() {      
		        	        @Override
		        	        public void onClick(DialogInterface dialog, int which) {
		        	          // TODO Auto-generated method stub
		        	          dialog.dismiss();
		        	          waitCount = -100;
		        	          
		        	          isFirstButtonTapped = false;
		        	        }
		        	     })
		        	     .setNegativeButton(secondApplicationName, new DialogInterface.OnClickListener() {      
			        	        @Override
			        	        public void onClick(DialogInterface dialog, int which) {
			        	          // TODO Auto-generated method stub 
			        	          isFirstButtonTapped	= false;
			        	          isSecondButtonTapped	= true;
			        	          
			        	          dialog.dismiss();
			        	          waitCount = -100;
			        	        }
			        	     })
		        	     .setNeutralButton(thirdApplicationName, new DialogInterface.OnClickListener() {      
			        	        @Override
			        	        public void onClick(DialogInterface dialog, int which) {
			        	          // TODO Auto-generated method stub
			        	          isFirstButtonTapped	= false;
			        	          isThirdButtonTapped	= true;
			        	          
			        	          dialog.dismiss();
			        	          waitCount = -100;
			        	        }
			        	     })
		        	     .setCancelable(false)
		        	     .show();
						break;
	
					case 5:
						alert = new AlertDialog.Builder(RunTask.this)
//		        	     .setIcon(R.drawable.app_icon)
		        	     .setTitle("이 앱이 맞나요? 맞다면 잠시만 기다려주세요.")
		        	     .setMessage("Play 스토어")
		        	     .setPositiveButton("다시 입력하기", new DialogInterface.OnClickListener() {      
		        	        @Override
		        	        public void onClick(DialogInterface dialog, int which) {
		        	          // TODO Auto-generated method stub
		        	          dialog.dismiss();
		        	          waitCount = -100;
		        	          
		        	          isFirstButtonTapped = false;
		        	        }
		        	     })
		        	     .setNegativeButton(secondApplicationName, new DialogInterface.OnClickListener() {      
			        	        @Override
			        	        public void onClick(DialogInterface dialog, int which) {
			        	          // TODO Auto-generated method stub
			        	          isFirstButtonTapped	= false;
			        	          isSecondButtonTapped	= true;
			        	          
			        	          dialog.dismiss();
			        	          waitCount = -100;
			        	        }
			        	     })
		        	     .setNeutralButton(thirdApplicationName, new DialogInterface.OnClickListener() {      
			        	        @Override
			        	        public void onClick(DialogInterface dialog, int which) {
			        	          // TODO Auto-generated method stub			        	          
			        	          isFirstButtonTapped	= false;
			        	          isThirdButtonTapped	= true;
			        	          
			        	          dialog.dismiss();
			        	          waitCount = -100;
			        	        }
			        	     })
		        	     .setCancelable(false)
		        	     .show();
						break;
						
					case 6:
						alert = new AlertDialog.Builder(RunTask.this)
//		        	     .setIcon(R.drawable.app_icon)
		        	     .setTitle("이 앱이 맞나요? 맞다면 잠시만 기다려주세요.")
		        	     .setMessage("계산기")
		        	     .setPositiveButton("다시 입력하기", new DialogInterface.OnClickListener() {      
		        	        @Override
		        	        public void onClick(DialogInterface dialog, int which) {
		        	          // TODO Auto-generated method stub
		        	          dialog.dismiss();
		        	          waitCount = -100;
		        	          
		        	          isFirstButtonTapped = false;
		        	        }
		        	     })
		        	     .setNegativeButton(secondApplicationName, new DialogInterface.OnClickListener() {      
			        	        @Override
			        	        public void onClick(DialogInterface dialog, int which) {
			        	          // TODO Auto-generated method stub			        	          
			        	          isFirstButtonTapped	= false;
			        	          isSecondButtonTapped	= true;
			        	          
			        	          dialog.dismiss();
			        	          waitCount = -100;
			        	         
			        	        }
			        	     })
		        	     .setNeutralButton(thirdApplicationName, new DialogInterface.OnClickListener() {      
			        	        @Override
			        	        public void onClick(DialogInterface dialog, int which) {
			        	          // TODO Auto-generated method stub
			        	          isFirstButtonTapped	= false;
			        	          isThirdButtonTapped	= true;
			        	          
			        	          dialog.dismiss();
			        	          waitCount = -100;
			        	        }
			        	     })
		        	     .setCancelable(false)
		        	     .show();
						break;
						
					default:
						break;
				}        		
            	
            }
        };
         
    	
    	private void decideApplication(double[] recordedCoef)
    	{
    		final double[] internetData			= {-0.963062,	0.075142,	-0.226297,	0.487118,	-0.086228,	0.249048,	-0.158028,	0.201420,	-0.109371};
    		final double[] kakaoTalkData		= {-0.953152,	0.410965,	0.091093,	0.508831,	-0.137057,	-0.140197,	-0.394197,	0.002791,	-0.055865};
//    		final double[] cameraData			= {-0.925105,	0.306008,	-0.306879,	0.458878,	-0.326471,	0.283620,	-0.298414,	0.267504,	-0.070930};
    		final double[] takeAPictureData		= {-0.804426,	-0.302438,	-0.441890,	0.066363,	-0.037769,	0.240489,	0.020555,	0.401051,	0.162489};
    		final double[] searchLocationData	= {-0.799382,	-0.266977,	-0.458895,	0.124653,	0.011340,	0.274566,	0.010658,	0.242166,	-0.021909};
    		final double[] galleryData			= {-0.939462,	0.376721,	-0.536168,	0.425054,	-0.224383,	0.359277,	-0.025893,	0.077647,	0.002772};
    		final double[] playstoreData		= {-0.836019,	0.174384,	-0.238049,	-0.019544,	-0.169116,	0.187428,	-0.014154,	0.353860,	-0.007630};
    		final double[] calculatorData		= {-0.965049,	0.172952,	-0.151534,	0.271836,	0.007282,	0.262189,	-0.018880,	0.209170,	0.015307};
    		final double[][] groupedData		= {internetData, kakaoTalkData, takeAPictureData, searchLocationData, galleryData, playstoreData, calculatorData};
    		
    		final int nOfAvailableApps		= groupedData.length;
    		//각 데이터와 euclidean distance를 계산하여 가장 작은 항목을 뽑아낸다.
    		
    		double shortestDistance			= 100.0;
    		double secondShortestDistance	= 100.0;
    		double thirdShortestDistance	= 100.0;
    		int indexOfShortestData 		= -1; 
    		int secondIndexOfShortestData	= -1;
    		int thirdIndexOfShortestData	= -1;
    		
    		for (int cnt = 0 ; cnt < nOfAvailableApps ; cnt++)
    		{
    			double tempSum				= 0.0;
    			for (int cnt2 = 0 ; cnt2 < 9 ; cnt2++)
    			{
    				tempSum 				+= Math.pow((groupedData[cnt][cnt2] - recordedCoef[cnt2]), 2); 
    			}
    			double tempDistance			= Math.sqrt(tempSum);
    			if (shortestDistance > tempDistance)
    			{
    				thirdShortestDistance	= secondShortestDistance;
    				secondShortestDistance	= shortestDistance;
    				shortestDistance		= tempDistance;
    				
    				thirdIndexOfShortestData	= secondIndexOfShortestData;
    				secondIndexOfShortestData	= indexOfShortestData;
    				indexOfShortestData		= cnt;
    			}
    			else if (secondShortestDistance > tempDistance)
    			{
    				thirdShortestDistance	= secondShortestDistance;
    				secondShortestDistance	= tempDistance;
    				
    				thirdIndexOfShortestData	= secondIndexOfShortestData;
    				secondIndexOfShortestData	= cnt;
    			}
    			else if (thirdShortestDistance > tempDistance)
    			{
    				thirdShortestDistance	= tempDistance;
    				
    				thirdIndexOfShortestData	= cnt;
    			}
    		}
    		
    		PackageManager pm = getPackageManager();
			String firstPackageName = null;
			String secondPackageName = null;
			String thirdPackageName = null;
    		
    		switch (indexOfShortestData)
    		{    			
				case 0:
				{
//					if (shortestDistance <= 0.48)
					{
						Log.i("DA", "DECIDED TO INTERNET due to : " + shortestDistance);
						firstPackageName = "com.android.browser";
					}
//					else
//					{
//						Log.i("DA", "closest to INTERNET, but DECIDED TO NOTHING due to : " + shortestDistance);
//						indexOfShortestData	= -100;
//					}
					break;
				}
					
				case 1:
				{
//					if (shortestDistance <= 0.51)
					{
						Log.i("DA", "DECIDED TO KAKAOTALK due to : " + shortestDistance);
						firstPackageName = "com.kakao.talk";
					}
//					else
//					{
//						Log.i("DA", "closest to KAKAOTALK, but DECIDED TO NOTHING due to : " + shortestDistance);
//						indexOfShortestData	= -100;
//					}					
					break;
				}
					
//				case 2:
//				{
//					if (shortestDistance <= 0.36)
//					{
//						Log.i("DA", "DECIDED TO CAMERA due to : " + shortestDistance);
//						firstPackageName = "com.android.camera";
//					}
//					else
//					{
//						Log.i("DA", "closest to CAMERA, but DECIDED TO NOTHING due to : " + shortestDistance);
//						indexOfShortestData	= -100;
//					}
//					break;
//				}
				
				case 2:
				{
					Log.i("DA", "DECIDED TO TAKE A PICTURE due to : " + shortestDistance);
					firstPackageName = "com.android.camera";
					break;
				}
				
				case 3:
				{
					Log.i("DA", "DECIDED TO SEARCH LOCATION due to : " + shortestDistance);
					firstPackageName = "com.google.android.apps.maps";
					break;
				}
				
				case 4:
				{
					Log.i("DA", "DECIDED TO GALLERY due to : " + shortestDistance);
					firstPackageName = "com.google.android.gallery3d";
					break;
				}
				
				case 5:
				{
					Log.i("DA", "DECIDED TO PLAY STORE due to : " + shortestDistance);
					firstPackageName = "com.android.vending";
					break;
				}

				case 6:
				{
					if (shortestDistance <= 0.51)
					{
						Log.i("DA", "DECIDED TO CALCULATOR due to : " + shortestDistance);
						firstPackageName = "com.android.calculator2";
					}
					else
					{
						Log.i("DA", "closest to CALCULATOR, but DECIDED TO NOTHING due to : " + shortestDistance);
						indexOfShortestData	= -100;
					}
					break;
				}
				
				default:
					break;
			}
    		
    		switch (secondIndexOfShortestData)
    		{
    			case 0:
    			{
    				Log.i("DA", "The second app is Internet due to : " + secondShortestDistance);
    				secondPackageName = "com.android.browser";
    				secondApplicationName = "인터넷";
    				break;
    			}
    			
    			case 1:
    			{
    				Log.i("DA", "The second app is KakaoTalk due to : " + secondShortestDistance);
    				secondPackageName = "com.kakao.talk";
    				secondApplicationName = "카카오톡";
    				break;
    			}
    			
    			case 2:
    			{
    				Log.i("DA", "The second app is Take a Picture due to : " + secondShortestDistance);
    				secondPackageName = "com.android.camera";    	
    				secondApplicationName = "사진찍기";
    				break;
    			}

    			case 3:
    			{
    				Log.i("DA", "The second app is Search Location due to : " + secondShortestDistance);
    				secondPackageName = "com.google.android.apps.maps";
    				secondApplicationName = "지도찾기";
    				break;
    			}
    			
    			case 4:
    			{
    				Log.i("DA", "The second app is Gallery due to : " + secondShortestDistance);
    				secondPackageName = "com.google.android.gallery3d";
    				secondApplicationName = "갤러리";
    				break;
    			}
    			
    			case 5:
    			{
    				Log.i("DA", "The second app is Play Store due to : " + secondShortestDistance);
    				secondPackageName = "com.android.vending";
    				secondApplicationName = "Play 스토어";
    				break;
    			}
    			
    			case 6:
    			{
    				Log.i("DA", "The second app is Calculator due to : " + secondShortestDistance);
    				secondPackageName = "com.android.calculator2";
    				secondApplicationName = "계산기";
    				break;
    			}
    		}
    		
    		switch (thirdIndexOfShortestData)
    		{
	    		case 0:
				{
					Log.i("DA", "The third app is Internet due to : " + thirdShortestDistance);
					thirdPackageName = "com.android.browser";
					thirdApplicationName = "인터넷";
					break;
				}
				
				case 1:
				{
					Log.i("DA", "The third app is KakaoTalk due to : " + thirdShortestDistance);
					thirdPackageName = "com.kakao.talk";
					thirdApplicationName = "카카오톡";
					break;
				}
				
				case 2:
				{
					Log.i("DA", "The third app is Take a Picture due to : " + thirdShortestDistance);
					thirdPackageName = "com.android.camera";    
					thirdApplicationName = "사진찍기";
					break;
				}
	
				case 3:
				{
					Log.i("DA", "The third app is Search Location due to : " + thirdShortestDistance);
					thirdPackageName = "com.google.android.apps.maps";
					thirdApplicationName = "지도찾기";
					break;
				}
				
				case 4:
				{
					Log.i("DA", "The third app is Gallery due to : " + thirdShortestDistance);
					thirdPackageName = "com.google.android.gallery3d";
					thirdApplicationName = "갤러리";
					break;
				}
				
				case 5:
				{
					Log.i("DA", "The third app is Play Store due to : " + thirdShortestDistance);
					thirdPackageName = "com.android.vending";
					thirdApplicationName = "Play 스토어";
					break;
				}
				
				case 6:
				{
					Log.i("DA", "The third app is Calculator due to : " + thirdShortestDistance);
					thirdPackageName = "com.android.calculator2";
					thirdApplicationName = "계산기";
					break;
				}
    		}
    		
    		//사용자에게 해당 앱이 맞는지를 확인하는 화면을 출력한다.
    		
    		mHandler.sendEmptyMessage(indexOfShortestData);
    		
    		waitCount	= 0;
    		
    		while (!bCheckRecordedClicked)
    		{
    			try
    			{
    				Thread.sleep(100);
    				waitCount++;
    				
    				if (waitCount < 0)
    				{
    					break;
    				}
    				else if (waitCount > 25)
    				{
    					alert.dismiss();
    					break;
    				}
    			}
    			catch (InterruptedException e)
    			{
    				
    			}
    		}
    		
    		//enable recordBtn
    		mHandler.sendEmptyMessage(-1);
    		
//    		indexOfShortestData가 -100 -> 입력한 음성에 해당하는 기능이 없음 -> 아무런 동작도 실행하지 않음.
    		if (indexOfShortestData != -100)
    		{
    			Log.i("DA", "indexOfShortestData is not -100");
    			
	    		if ( (isFirstButtonTapped == true) )
	    		{
		    		ApplicationInfo ai = null;
					try {
						ai = pm.getApplicationInfo(firstPackageName, PackageManager.GET_META_DATA);
					}
					catch (NameNotFoundException e) {
					}
					String labelName = pm.getApplicationLabel(ai).toString();
					Intent intent = pm.getLaunchIntentForPackage(firstPackageName);
					startActivity(intent);
	    		}
	    		else if ( (isSecondButtonTapped == true))
	    		{
	    			Log.i("DA", "Second App Button is Tapped");
	    			
		    		ApplicationInfo ai = null;
					try {
						ai = pm.getApplicationInfo(secondPackageName, PackageManager.GET_META_DATA);
					}
					catch (NameNotFoundException e) {
					}
					String labelName = pm.getApplicationLabel(ai).toString();
					Intent intent = pm.getLaunchIntentForPackage(secondPackageName);
					startActivity(intent);
	    		}
	    		else if ( (isThirdButtonTapped == true) )
	    		{
	    			Log.i("DA", "Third App Button is Tapped");
	    			
		    		ApplicationInfo ai = null;
					try {
						ai = pm.getApplicationInfo(thirdPackageName, PackageManager.GET_META_DATA);
					}
					catch (NameNotFoundException e) {
					}
					String labelName = pm.getApplicationLabel(ai).toString();
					Intent intent = pm.getLaunchIntentForPackage(thirdPackageName);
					startActivity(intent);
	    		}
    		}
    		
    		isFirstButtonTapped = true;
    		isSecondButtonTapped = false;
    		isThirdButtonTapped = false;
    		
    		//만약 2초 내에 터치하지 않으면 해당 앱을 실행하고, 터치하면 다시 한번 녹음하게 한다.
    		//두번째 결과에는 가까운 순서로 세 개의 앱을 리스트로 보여주고 선택할 수 있도록 한다.
    	}
    	
    	private short[] normalization(short[] rawShort)
    	{
    		short biggest = 0;
    		biggestValues.removeAll(biggestValues);
    		
    		for (int i = 0; i < rawShort.length; i++)
    		{
				short s = rawShort[i];
				if (Math.abs(s) > biggest)
					biggest = (short)Math.abs(s);
			}
    		Log.i("NM", "biggest raw datum is " + biggest);
    		
    		float ratio	= (float)standardForNormalization / biggest;
    		
    		Log.i("NM", "ratio is " + ratio);
    		
    		for (int i = 0; i < rawShort.length; i++)
    		{
				rawShort[i] = (short)(rawShort[i] * ratio);				
			}
    		
    		//1000으로 했을 때 오차율이 크다고 판단
    		//250으로 줄여서 시도 예정.
    		int nOfFrames	= rawShort.length / 250;
    		
    		Log.i("NM", "The Number of Frames is " + nOfFrames);
    		
    		for (int cnt = 0 ; cnt < nOfFrames ; cnt++)
    		{
    			short tempBiggest = 0;
    			short tempCutline =  (250 + cnt*250 <= rawShort.length) ? (short)(250 + cnt*250) : (short)rawShort.length;
    			Log.i("NM", "temp Cut Line :" + tempCutline);
    			for (int cnt2 = 0+cnt*250 ; cnt2 < tempCutline ; cnt2++)	
    			{
    				if (Math.abs(rawShort[cnt2]) > tempBiggest)
    					tempBiggest	= (short) Math.abs(rawShort[cnt2]);
    			}
    			biggestValues.add(tempBiggest);
    			Log.i("NM", "biggestValues[" + cnt + "] = " + biggestValues.get(cnt));
    		}
    		
    		
    		
    		return rawShort;
    	}

    	@Override
    	public void run() {
    		File oRawFile												= null;
    		short[] aRawInShort											= null;
    		short[] aVoiceDataInShort									= null;

    		Log.i("INFO", "recordStart() - [");
    		recordStart();
    		Log.i("INFO", "] - recordStart()");

    		Log.i("INFO", "recordToFile() - [");
    		oRawFile													= recordToFile();
    		Log.i("INFO", "] - recordToFile()");

    		Log.i("INFO", "convertToWav() - [");
    		convertToWav(oRawFile);
    		Log.i("INFO", "] - convertToWav()");
 
    		Log.i("INFO", "convertToShort() - [");
    		aRawInShort													= convertToShort(oRawFile);
    		Log.i("INFO", "] - convertToShort()");
    		
    		Log.i("INFO", "aRawInShort.length = " + aRawInShort.length);
    		
    		if (aRawInShort.length == 0)
			{
    			mHandler.sendEmptyMessage(-1);			
    			return;
			}
    		
    		Log.i("INFO", "detectEndPoint() - [");
    		EndPointDetection oEPD										= new EndPointDetection(aRawInShort, RECORDER_SAMPLERATE);
    		aVoiceDataInShort											= oEPD.detectEndPoint();
    		Log.i("INFO", "] - detectEndPoint()");
    		
    		if (aVoiceDataInShort.length == 0)
    		{
    			mHandler.sendEmptyMessage(-1);			
    			return;
    		}
    		
    		Log.i("INFO", "normalization() - [");
    		aVoiceDataInShort											= normalization(aVoiceDataInShort);
    		Log.i("INFO", "] - normalization()");

    		Log.i("SIZE", "ORG ShortArraySize: "+ aRawInShort.length);
    		Log.i("SIZE", "NEW ShortArraySize: "+ aVoiceDataInShort.length);
    		
    		convertToWav(aVoiceDataInShort);

    		Log.i("INFO", "findCoefficient() - [");
    		LinearPredictiveCoding oLPC									= new LinearPredictiveCoding();
    		double[] aLPCInDouble										= oLPC.findCoefficient(aVoiceDataInShort, RECORDER_SAMPLERATE);
    		Log.i("INFO", "] - findCoefficient()");

    		for (int i = 0;i < aLPCInDouble.length;i++) {
//    			Log.i("LPC", "Array["+ i +"] ::("+ aLPCInDouble[i] +")");
    			Log.i("LPC", "" + aLPCInDouble[i]);
    		}
    		
    		Log.i("INFO", "decideApplication() - [");
    		
    		decideApplication(aLPCInDouble);
    		
    		Log.i("INFO", "] - decideApplication()");
    		
    		Log.i("INFO", "findFeature() - [");
//    		ExtractFeature oFeature										= new ExtractFeature(aVoiceDataInShort, RECORDER_SAMPLERATE);
//    		oFeature.doExtract();
    		Log.i("INFO", "] - findFeature()");
    		
    		Log.i("INFO", "DTW - [");
    		
//    		String tempStr = "";
//    		
//    		for (int cnt = 0 ; cnt < aVoiceDataInShort.length ; cnt++)
//    		{
//    			if (cnt % 2 == 0)
//    			{
//    				tempStr += Short.toString(aVoiceDataInShort[cnt]);
//    				tempStr += ", ";
//    			}
//    		}
//    		Log.i("INFO", tempStr);
    		
//    		LPC에서 인터넷 으로 인식한 단어의 데이터
//    		음성 데이터 약 7000~8000개를 한꺼번에 넘기면 메모리 부족으로 죽어버리니까.
//    		이전에 했던 열쇠이론으로 특징값만 추출한 다음 비교해 보는 것으로 한다.
//    		참고로 열쇠이론 값은 text:biggestValues 로 검색하면 나온다.
    		
//    		같은 template & template2에서는 항상 일정한 값이 나온다. 그렇다면, biggestValue를 추출하는 데서 문제가 생기는 건가?
    		
//    		인터넷 이랑 사진촬영 이랑 값 차이가 너무 안나..
    		
//    		short[] biggestValuesArray = new short[biggestValues.size()];
//    		for (int cnt = 0 ; cnt < biggestValues.size() ; cnt++)
//    		{
//    			biggestValuesArray[cnt] = biggestValues.get(cnt);
//    		}
    		
////    		chuckSize=250, word:사진촬영
//    		short[] template = {0, 435, 358, 364, 182, 202, 163, 124, 200, 149, 185, 340, 761, 1100, 792, 1214, 1992, 5101, 5407, 5390, 5720, 6279, 4276, 4038, 8258, 8987, 10000, 9336, 7244, 6051, 4954, 3673, 3153, 6857, 2959, 1031, 3805, 4887, 5078, 4290, 4217, 3837, 4770, 3345, 3656, 3238, 3521, 2835, 2979, 1989, 2288, 1758, 1368, 820, 544, 634, 564, 502, 373, 335, 301, 291, 359, 267, 308, 298, 268, 249, 175, 193, 219, 199, 156};
////    		short[] template2 = {641, 449, 429, 406, 6666, 6931, 4013, 6877, 10000, 8676, 7398, 3391, 518, 483, 6020, 422};
//    		
//    		DTW dtw														= new DTW(biggestValuesArray, template);
////    		DTW dtw														= new DTW(template, template2);
//    		dtw.compute();
//    		Log.i("DTW", dtw.toString());
    		    		
    		Log.i("INFO", "] - DTW");
 
    	}
    }

}